﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Text;
using OfficeOpenXml;
using UnityEditor;
using UnityEngine;

namespace ExcelExpoter.Editor
{
    public static class ExporterTool
    {
        public static string ExcelPath;
        public static string LuaDataPath;
        public static string ByteDataPath;
        public static string CsScriptPath;

        private static string _assetPath = "";
        private static string _rootPath = "";
        public static string AssetPath
        {
            get
            {
                if (string.IsNullOrEmpty(_assetPath))
                {
                    var root = RootPath;
                    if (string.IsNullOrEmpty(root)) return "";
                    var index = root.IndexOf("Assets", StringComparison.Ordinal);
                    _assetPath = root.Substring(index);
                }
                return _assetPath;
            }
        }
        private static string RootPath
        {
            get
            {
                if (string.IsNullOrEmpty(_rootPath))
                {
                    var paths = UnityEditor.AssetDatabase.FindAssets("ExcelExporterWindow");
                    if (paths.Length <= 0 || paths.Length > 1) return null;
                    var filePath = AssetDatabase.GUIDToAssetPath(paths[0]);
                    var dirInfo = new DirectoryInfo(filePath);
                    _rootPath = dirInfo.Parent?.FullName;
                }
                return _rootPath;
            }
        }
        
        public static string PortoToolPath => $"{RootPath}/ProtoTool/protoc.exe";
        public static string XsltPath => $"{RootPath}/Xslt";

        public static string ProtoDataPath => $"{ExcelPath}/Proto";
        
        public static readonly List<ExcelItem> AllExcel = new List<ExcelItem>();
        public static ExporterHash HashConfig;
        
        private static readonly uint StartContentRow = 4;
        private static readonly char[] SplitSymbols = { '|' };
        
        //
        private const string CsPackageName = "com.CBPK.proto";

        #region Lua
        
        public static void ExporterToLua()
        {
            foreach (var excel in AllExcel)
            {
                if (!excel.Select) continue;
                ExporterInternal(excel);
                CheckHash(excel);
            }
            EditorUtility.ClearProgressBar();
            HashConfig.Save();
            AssetDatabase.Refresh();
        }

        private static void ExporterInternal(ExcelItem item)
        {
            FileStream fs = null;
            try
            {
                fs = File.OpenRead(item.FullPath);
            }
            catch (IOException e)
            {
                Debug.LogError($"表已在其它应用打开, 请关闭后执行导出操作.\n{e.Message}");
                return;
            }
            EditorUtility.DisplayProgressBar($"{item.Name}", "读取Excel信息 ...", 0.5f);
            ExcelPackage package = new ExcelPackage(fs);
            ExcelWorkbook book = package.Workbook;
            ExcelWorksheets sheets = book.Worksheets;
            foreach (var sheet in sheets)
            {
                var sheetName = sheet.Name.Trim();
                if (!sheetName.StartsWith("#")) continue;
                sheetName = sheetName.Substring(1, sheetName.Length - 1);

                var hashCode = sheet.GetHashCode(sheet).ToString();
                if (HashConfig.IsSheetHashSame($"{item.Name}_{sheetName}", hashCode) && !item.Select) continue;

                string savePath = Path.Combine(LuaDataPath, $"E_{sheetName}.lua");
                string content = GenLuaFile(sheet);
                if (string.IsNullOrEmpty(content)) continue;
                EditorUtility.DisplayProgressBar($"{sheet.Name}", "string 写入 Lua文件 ...", 0.45f);
                File.WriteAllText(savePath, content);
            }
            fs.Dispose();
            fs.Close();
        }
        
        private static string GenLuaFile(ExcelWorksheet sheet)
        {
            List<ColumnInfo> columnDesc = GetColumnInfo(sheet);
            List<string> idTable = new List<string>();

            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append("--[[Notice:This lua config file is auto generate by Xls2Lua Tools，don't modify it manually! --]]\n");
            if (null == columnDesc || columnDesc.Count <= 0)
            {
                return stringBuilder.ToString();
            }
            //创建索引
            Dictionary<string, int> fieldIndexMap = new Dictionary<string, int>();
            for (int i = 0; i < columnDesc.Count; i++)
            {
                fieldIndexMap[columnDesc[i].Name] = i + 1;
            }
            //创建数据块的索引表
            stringBuilder.Append("local fieldIdx = {");
            foreach (var cur in fieldIndexMap)
            {
                stringBuilder.Append(string.Format("{0} = {1} ,", cur.Key, cur.Value));
            }
            stringBuilder.Append("}\n");

            //创建数据块
            stringBuilder.Append("local data = {");
            int rows = sheet.Dimension.Rows;
            //逐行读取并处理
            for (uint i = StartContentRow; i <= rows; i++)
            {
                EditorUtility.DisplayProgressBar($"{sheet.Name}", "Sheet 转 Lua 数据 ...", (float) i / rows);
                StringBuilder oneRowBuilder = new StringBuilder();
                oneRowBuilder.Append("{");
                //对应处理每一列
                for (int j = 1; j <= columnDesc.Count; j++)
                {
                    ColumnInfo curColumn = columnDesc[j - 1];
                    string content = sheet.GetValue<string>((int)i, curColumn.Index);
                    if (string.IsNullOrEmpty(content))
                    {
                        Debug.LogError($"表 {sheet.Name} 数据为空! 位于第 {i} 行 第 {j} 列!");
                    }
                    if (j == 1)
                    {
                        idTable.Add(content);
                    }
                    if (FieldType.CStruct != curColumn.Type)
                    {
                        FieldType fieldType = curColumn.Type;
                        //如果不是数组类型的话
                        if (!curColumn.IsArray)
                        {
                            content = GetLuaValue(fieldType, content);
                            oneRowBuilder.Append(content);
                        }
                        else
                        {
                            StringBuilder tmpBuilder = new StringBuilder("{");
                            var tmpStringList = content?.Split(SplitSymbols, StringSplitOptions.RemoveEmptyEntries);
                            for (int k = 0; k < tmpStringList?.Length; k++)
                            {
                                tmpStringList[k] = GetLuaValue(fieldType, tmpStringList[k]);
                                tmpBuilder.Append(tmpStringList[k]);
                                if (k != tmpStringList.Length - 1)
                                {
                                    tmpBuilder.Append(",");
                                }
                            }

                            oneRowBuilder.Append(tmpBuilder);
                            oneRowBuilder.Append("}");
                        }
                    }
                    else
                    {
                        //todo:可以处理结构体类型的字段
                        throw new Exception("暂不支持结构体类型的字段！");
                    }

                    if (j != columnDesc.Count)
                    {
                        oneRowBuilder.Append(",");
                    }
                }

                oneRowBuilder.Append("},");
                stringBuilder.Append(string.Format("\n{0}", oneRowBuilder));
            }
            //当所有的行都处理完成之后
            stringBuilder.Append("}\n");
            stringBuilder.Append("local idTable = {");
            for (int i = 0; i < idTable.Count; i++)
            {
                stringBuilder.Append($"[{idTable[i]}] = {i + 1} ,");
            }
            stringBuilder.Append("}\n");
            stringBuilder.AppendLine("data.IdTable = idTable");
            stringBuilder.AppendLine("data.getById = function(self, id)");
            stringBuilder.AppendLine("\tid = tonumber(id)");
            stringBuilder.AppendLine("\treturn self[self.IdTable[id]]");
            stringBuilder.AppendLine("end");
            //设置元表
            string str =
                "local mt = {}\n" +
                "mt.__index = function(a,b)\n" +
                "\tif fieldIdx[b] then\n" +
                "\t\treturn a[fieldIdx[b]]\n" +
                "\tend\n" +
                "\treturn nil\n" +
                "end\n" +
                "mt.__newindex = function(t,k,v)\n" +
                "\terror('do not edit config')\n" +
                "end\n" +
                "mt.__metatable = false\n" +
                "for _,v in ipairs(data) do\n\t" +
                "setmetatable(v,mt)\n" +
                "end\n" +
                "return data";
            stringBuilder.Append(str);
            return stringBuilder.ToString();
        }
        
        private static List<ColumnInfo> GetColumnInfo(ExcelWorksheet sheet)
        {
            int columnCount = GetSheetColumns(sheet);
            List<ColumnInfo> columnDescList = new List<ColumnInfo>();
            for (int i = 1; i <= columnCount; i++)
            {
                string comment = sheet.GetValue<string>(1, i).Trim();
                comment = string.IsNullOrWhiteSpace(comment) ? comment : comment.Split('\n')[0];
                string typeStr = sheet.GetValue<string>(2, i).Trim();
                string nameStr = sheet.GetValue<string>(3, i).Trim();

                bool isArray = typeStr.Contains("[]");
                typeStr = typeStr.Replace("[]", "");
                FieldType fieldType;
                if (typeStr.ToLower().StartsWith("struct-"))
                {
                    typeStr = typeStr.Remove(0, 7);
                    fieldType = FieldType.CStruct;
                }
                else if (typeStr.ToLower().StartsWith("enum-"))
                {
                    typeStr.Remove(0, 5);
                    fieldType = FieldType.CEnum;
                }
                else
                {
                    fieldType = StringToFieldType(typeStr);
                }
                ColumnInfo columnDesc = new ColumnInfo();
                columnDesc.Index = i;
                columnDesc.Comment = comment;
                columnDesc.TypeStr = typeStr;
                columnDesc.Name = nameStr;
                columnDesc.Type = fieldType;
                columnDesc.IsArray = isArray;
                columnDescList.Add(columnDesc);
            }
            return columnDescList;
        }
        
        private static FieldType StringToFieldType(string str)
        {
            str = str.Trim();
            str = str.ToLower();
            if ("int32" == str)
                return FieldType.CInt32;
            else if ("int64" == str)
                return FieldType.CInt64;
            else if ("bool" == str)
                return FieldType.CBool;
            else if ("float" == str)
                return FieldType.CFloat;
            else if ("double" == str)
                return FieldType.CDouble;
            else if ("string" == str)
                return FieldType.CString;
            else if ("uint32" == str)
                return FieldType.CUint32;
            else if ("uint64" == str)
                return FieldType.CUint64;
            else if ("fixed32" == str)
                return FieldType.CFixed32;
            else if ("fixed64" == str)
                return FieldType.CFixed64;
            return FieldType.CUnknown;
        }
        
        private static int GetSheetColumns(ExcelWorksheet sheet)
        {
            int coloum = sheet.Dimension.Columns;
            for (int i = 1; i <= coloum; i++)
            {
                string temp1 = sheet.GetValue<string>(1, i);
                string temp2 = sheet.GetValue<string>(2, i);
                if (string.IsNullOrWhiteSpace(temp1) || string.IsNullOrWhiteSpace(temp2))
                {
                    return i;
                }
            }
            return coloum;
        }
        
        private static string GetLuaValue(FieldType fieldType, string value)
        {
            if (FieldType.CString == fieldType)
            {
                if (string.IsNullOrWhiteSpace(value))
                {
                    return "\"\"";
                }

                return string.Format("\"{0}\"", value);
            }
            else if (FieldType.CEnum == fieldType)
            {
                //todo:可以具体地相应去处理枚举型变量
                string enumKey = value.Trim();
                return enumKey;
            }
            else if (FieldType.CBool == fieldType)
            {
                bool isOk = StringToBoolean(value);
                return isOk ? "true" : "false";
            }
            else
            {
                return string.IsNullOrEmpty(value.Trim()) ? "0" : value.Trim();
            }
        }
        
        private static bool StringToBoolean(string value)
        {
            value = value.ToLower().Trim();
            if (string.IsNullOrEmpty(value))
            {
                return true;
            }

            if ("false" == value)
            {
                return false;
            }

            int num = -1;
            if (int.TryParse(value, out num))
            {
                if (0 == num)
                {
                    return false;
                }
            }

            return true;
        }
        
        #endregion

        #region Cs

        public static void ExportToCs()
        {
            //生成Proto 文件
            var protoList = GenProto();
            //生成数据模板类 ConfigProto.cs
            GenerateProtoCSfile.GenerateConfigProtoCsFile();
            //生成配置数据类 ConfigData.cs
            CreateConfigScript(protoList);

            //生成字节|文本数据
            var excelList = ExportByteConfig();
            //生成数据路径映射表
            ExportExcelMap(excelList);
            
            EditorUtility.ClearProgressBar();
            HashConfig.Save();
            AssetDatabase.Refresh();
        }

        private static List<CreateConfigScriptData> GenProto()
        {
            List<CreateConfigScriptData> validExcel = new List<CreateConfigScriptData>();
            for (int j = 0; j < AllExcel.Count; j++)
            {
                var excel = AllExcel[j];
                if (!excel.Select) continue;
                StringBuilder str = new StringBuilder();
                try
                {
                    FileStream stream = null;
                    stream = File.OpenRead(excel.FullPath);
                    ExcelPackage excelReader = new ExcelPackage(stream);
                    ExcelWorkbook result = excelReader.Workbook;
                    ExcelWorksheet sheet = result.Worksheets.First();
                    stream.Close();
                    if (sheet.Dimension == null) return validExcel;

                    int columns = sheet.Dimension.End.Column;
                    int rows = sheet.Dimension.End.Row;

                    if (rows < StartContentRow)
                    {
                        Debug.LogError($"表头格式不正确! {excel.Name}");
                        return validExcel;
                    }

                    str.AppendLine($"package {CsPackageName};");
                    str.AppendLine($"message {excel.Name}Config" + @"{");

                    //读取表头
                    for (int i = 1; i <= columns; i++)
                    {
                        EditorUtility.DisplayProgressBar($"{sheet.Name}", "读取Sheet 表头数据 ...", (float) i / columns);
                        string explain = sheet.GetValue<string>(1, i);
                        string type = sheet.GetValue<string>(2, i);
                        if (string.IsNullOrEmpty(type))
                        {
                            Debug.LogError($"表 {excel.Name} 第{i}列类型为NULL.");
                            continue;
                        }

                        string valueName = sheet.GetValue<string>(3, i);
                        if (string.IsNullOrEmpty(valueName))
                        {
                            Debug.LogError($"表 {excel.Name} 第{i}列变量名为NULL.");
                            continue;
                        }
                        if (i == 1) validExcel.Add(new CreateConfigScriptData(){ExcelName = excel.Name, TypeName = type, VariableName = valueName});

                        valueName = valueName.TrimEnd(' ');
                        if (type == "int")
                            type = "int32";
                        else if (type == "long")
                            type = "int64";
                        str.AppendLine($"\trequired {type} {valueName} = {i};  //{explain}");
                    }

                    str.AppendLine(@"}");
                    str.AppendLine($"message {excel.Name}ConfigData" + @"{");
                    str.AppendLine($"\trepeated {excel.Name}Config config = 1;");
                    str.AppendLine(@"}");
                }
                catch (IOException e)
                {
                    Debug.LogError($"解析Excel表 {excel.Name} 失败. {e.Message}");
                }
                try
                {
                    EditorUtility.DisplayProgressBar($"{excel.Name}", "写入Proto 文件 ...", (float)(j + 1f) / AllExcel.Count);
                    if (!Directory.Exists(ProtoDataPath)) Directory.CreateDirectory(ProtoDataPath);
                    var filePath = ProtoDataPath + "/" + excel.Name + ".proto";
                    using (System.IO.FileStream fsConfig = System.IO.File.Create(filePath))
                    {
                        using (System.IO.BinaryWriter bwConfig = new System.IO.BinaryWriter(fsConfig, Encoding.UTF8))
                        {
                            char[] data = str.ToString().ToCharArray();
                            bwConfig.Write(data);
                            bwConfig.Close();
                        }
                        fsConfig.Close();
                    }
                }
                catch (IOException e)
                {
                    Debug.LogError($"写入Proto文件 {excel.Name} 失败. {e.Message}");
                }
            }
            return validExcel;
        }

        private static void CreateConfigScript(List<CreateConfigScriptData> scriptDataList)
        {
            EditorUtility.DisplayProgressBar("Excel 打表进度", "生成数据集 ConfigData.cs 文件 ...", 0.8f);
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.AppendLine("// 当前 脚本 由工具自动生成! 不要手动修改!!!");
            stringBuilder.AppendLine($"// CreateTime: {System.DateTime.Now}");
            stringBuilder.AppendLine("");
            stringBuilder.AppendLine("using System.Collections.Generic;");
            stringBuilder.AppendLine("using ExcelExporter.Runtime;");
            stringBuilder.AppendLine($"namespace {CsPackageName}");
            stringBuilder.AppendLine("{");
            for (int i = 0; i < scriptDataList.Count; i++)
            {
                CreateConfigScriptData tempData = scriptDataList[i];
                stringBuilder.AppendLine($"\tpublic partial class {tempData.ExcelName}ConfigData : IConfigData");
                stringBuilder.AppendLine("\t{");
                stringBuilder.AppendLine(
                    $"\t\tprivate static Dictionary<{tempData.TypeName}, {tempData.ExcelName}Config> _{tempData.ExcelName}Dic;");
                stringBuilder.AppendLine("\t\tpublic global::ProtoBuf.IExtensible LoadDataById(int id) {");
                stringBuilder.AppendLine($"\t\t\treturn _{tempData.ExcelName}Dic[id];");
                stringBuilder.AppendLine("\t\t}");
                stringBuilder.AppendLine("\t\tpublic List<global::ProtoBuf.IExtensible> DataList()");
                stringBuilder.AppendLine("\t\t{");
                stringBuilder.AppendLine(
                    "\t\t\tList<global::ProtoBuf.IExtensible> dataList = new List<global::ProtoBuf.IExtensible>();");
                stringBuilder.AppendLine($"\t\t\tforeach (var value in _{tempData.ExcelName}Dic.Values)");
                stringBuilder.AppendLine("\t\t\t{ dataList.Add(value); }");
                stringBuilder.AppendLine("\t\t\treturn dataList;");
                stringBuilder.AppendLine("\t\t}");
                stringBuilder.AppendLine(
                    $"\t\tpublic Dictionary<{tempData.TypeName}, {tempData.ExcelName}Config> {tempData.ExcelName}Dic");
                stringBuilder.AppendLine("\t\t{ get {");
                stringBuilder.AppendLine($"\t\t\t\treturn _{tempData.ExcelName}Dic;");
                stringBuilder.AppendLine("\t\t\t} }");
                stringBuilder.AppendLine("\t\tpublic void InitData() {");
                stringBuilder.AppendLine(
                    $"\t\t\t_{tempData.ExcelName}Dic = new Dictionary<{tempData.TypeName}, {tempData.ExcelName}Config>();");
                stringBuilder.AppendLine("\t\t\tforeach (var value in config) {");
                stringBuilder.AppendLine(
                    $"\t\t\t\t_{tempData.ExcelName}Dic.Add(value.{tempData.VariableName}, value);");
                stringBuilder.AppendLine("\t\t\t} }");
                stringBuilder.AppendLine("\t}");
            }

            stringBuilder.AppendLine("}");
            stringBuilder.AppendLine("public class ConfigList");
            stringBuilder.AppendLine("{");
            for (int i = 0; i < scriptDataList.Count; i++)
            {
                stringBuilder.AppendLine(
                    $"\tpublic static readonly string {scriptDataList[i].ExcelName}Name = \"{scriptDataList[i].ExcelName}\";");
            }

            stringBuilder.AppendLine("}");
            string filePath = CsScriptPath + "/ConfigData.cs";
            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }

            using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate))
            {
                //获得字节数组
                byte[] writeData = System.Text.Encoding.UTF8.GetBytes(stringBuilder.ToString());
                //开始写入
                fs.Write(writeData, 0, writeData.Length);
                //清空缓冲区、关闭流
                fs.Flush();
                fs.Close();
            }
            EditorUtility.DisplayProgressBar("Excel 打表进度", "完成", 1);
            EditorUtility.ClearProgressBar();
        }

        private static List<ExportCsInfo> ExportByteConfig()
        {
            List<ExportCsInfo> csInfos = new List<ExportCsInfo>();
            for (int i = 0; i < AllExcel.Count; i++)
            {
                var excel = AllExcel[i];
                EditorUtility.DisplayProgressBar($"{excel.Name}", "生成 Byte 和 Text ...", (i + 1f) / AllExcel.Count);
                if (!excel.Select) continue;

                byte[] dataConfig = null;
                try
                {
                    using (FileStream stream = File.OpenRead(excel.FullPath))
                    {
                        var obj = CreateData(stream, excel.Name);
                        using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
                        {
                            ProtoBuf.Serializer.Serialize(ms, obj);
                            dataConfig = ms.ToArray();
                            ms.Close();
                        }
                        stream.Close();
                    }
                }
                catch (SerializationException e)
                {
                    Debug.LogError($"读取文件流出错.{excel.Name} {e.Message}");
                }
                
                var baseBytePath = ByteDataPath + "/ByteData";
                var pathByteConfig = $"{baseBytePath}/{excel.Name}.bytes";

                int startIndex = 0;
                string dataPath = "";
                if ((startIndex = pathByteConfig.IndexOf("Resources", 0, StringComparison.Ordinal)) > 0)
                {
                    dataPath = pathByteConfig.Substring(startIndex + 10);
                }
                else
                {
                    startIndex = pathByteConfig.IndexOf("Assets", 0, StringComparison.Ordinal);
                    dataPath = pathByteConfig.Substring(startIndex);
                }

                var typeName = $"{CsPackageName}.{excel.Name}ConfigData";
                csInfos.Add(new ExportCsInfo(typeName, excel.Name, dataPath));
                
                if (dataConfig == null) continue;
                if (HashConfig.IsGenerateByte)
                {
                    EditorUtility.DisplayProgressBar($"{excel.Name}", "生成 Byte 文件 ...", 0.45f);
                    if (!Directory.Exists(baseBytePath))
                    {
                        Directory.CreateDirectory(baseBytePath);
                    }
                    using (System.IO.FileStream fStreamConfig = System.IO.File.Create(pathByteConfig))
                    {
                        using (System.IO.BinaryWriter bwConfig = new System.IO.BinaryWriter(fStreamConfig, Encoding.UTF8))
                        {
                            bwConfig.Write(dataConfig);
                            bwConfig.Close();
                        }
                        fStreamConfig.Close();
                    }
                }
                if (HashConfig.IsGenerateText)
                {
                    EditorUtility.DisplayProgressBar($"{excel.Name}", "生成 Text 文件 ...", 0.45f);
                    var basePath = ByteDataPath + "/TextData";
                    if (!Directory.Exists(basePath))
                    {
                        Directory.CreateDirectory(basePath);
                    }
                    var pathConfig = $"{basePath}/{excel.Name}.txt";
                    using (System.IO.FileStream fsConfig = System.IO.File.Create(pathConfig))
                    {
                        using (System.IO.StreamWriter bwConfig = new System.IO.StreamWriter(fsConfig, Encoding.UTF8))
                        {
                            string data = Encoding.UTF8.GetString(dataConfig);
                            bwConfig.Write(data);
                            bwConfig.Close();
                        }

                        fsConfig.Close();
                    }
                }

                CheckHash(excel);
            }
            return csInfos;
        }

        /// <summary>
        /// 创建 Excel 导出的字节或者文本 文件 路径映射表
        /// </summary>
        /// <param name="classNameDic"></param>
        private static void ExportExcelMap(List<ExportCsInfo> classNameDic)
        {
            EditorUtility.DisplayProgressBar($"总配置", "生成 数据路径 映射表 ...", 0.45f);
            var fileConfig = $"{ByteDataPath}/ConfigDataBase.bytes";
            using (System.IO.FileStream fsConfig = System.IO.File.Create(fileConfig))
            {
                using (System.IO.BinaryWriter bwConfig = new System.IO.BinaryWriter(fsConfig, Encoding.UTF8))
                {
                    StringBuilder stringBuilder = new StringBuilder();
                    foreach (var value in classNameDic)
                    {
                        stringBuilder.AppendLine($"{value.ClassType}:{value.FileName}:{value.FilePath}");
                    }

                    bwConfig.Write(Encoding.UTF8.GetBytes(stringBuilder.ToString()));
                    bwConfig.Close();
                }
                fsConfig.Close();
            }
        }

        private static System.Object CreateData(FileStream stream, string name)
        {
            ExcelPackage excelReader = new ExcelPackage(stream);
            ExcelWorkbook result = excelReader.Workbook;
            ExcelWorksheet workSheet = result.Worksheets.First();

            //单个数据
            Type dataType = GetTypeByName(CsPackageName + "." + name + "Config");
            if (dataType == null)
            {
                Debug.LogError("type====" + name + "===is not find");
                return null;
            }

            //列表数据
            Type configType = GetTypeByName(CsPackageName + "." + name + "ConfigData");
            if (configType == null)
            {
                Debug.LogError("type=====" + name + "Config=======is not find");
                return null;
            }

            //获取列表变量
            System.Reflection.FieldInfo field = configType.GetField("_config",
                System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.FlattenHierarchy |
                System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance |
                System.Reflection.BindingFlags.GetField);


            if (field == null)
            {
                Debug.LogError("field not find !!! ======" + configType.Name + "._config");
                return null;
            }

            int columns = workSheet.Dimension.End.Column;
            int rows = workSheet.Dimension.End.Row;
            System.Reflection.PropertyInfo[] tmpFields = dataType.GetProperties(
                System.Reflection.BindingFlags.SetField | System.Reflection.BindingFlags.Public |
                System.Reflection.BindingFlags.Instance);

            System.Object configObj = Activator.CreateInstance(configType);
            IList mDataList = field.GetValue(configObj) as IList;
            for (int i = 0; i < rows; i++)
            {
                if (i > 2)
                {
                    System.Object target = Activator.CreateInstance(dataType);
                    if (columns > 0)
                    {
                        string dd = workSheet.GetValue<string>(i + 1, 1);
                        if (string.IsNullOrEmpty(dd))
                        {
                            break;
                        }
                    }

                    for (int j = 0, fieldIndex = 0; j < columns; j++)
                    {
                        string kk = workSheet.GetValue<string>(i + 1, j + 1);

                        if (fieldIndex >= tmpFields.Length)
                        {
                            continue;
                        }

                        TypeCode tpy = Type.GetTypeCode(tmpFields[fieldIndex].PropertyType);

                        string value = workSheet.GetValue<string>(i + 1, j + 1);
                        if (string.IsNullOrEmpty(value))
                        {
                            value = "";
                        }

                        value = value.TrimEnd(' ');
                        if (!tmpFields[fieldIndex].CanWrite)
                        {
                            continue;
                        }

                        switch (tpy)
                        {
                            case TypeCode.Int32:

                                if (kk != null)
                                {

                                    if (string.IsNullOrEmpty(value))
                                    {
                                        value = "0";
                                    }

                                    try
                                    {
                                        tmpFields[fieldIndex].SetValue(target, Int32.Parse(value), null);
                                    }
                                    catch (System.Exception ex)
                                    {
                                        Debug.LogError(ex.ToString());
                                        Debug.LogError(string.Format("Data error: {0} : {2}:[{1}] is not int", name,
                                            workSheet.GetValue<string>(i + 1, j + 1), tmpFields[j].Name));

                                        string key = workSheet.GetValue<string>(i + 1, 1);
                                        int keyValue;
                                        if (int.TryParse(key, out keyValue))
                                        {
                                            Debug.LogError("上条错误对应的ID：" + keyValue);
                                        }
                                    }

                                }
                                else
                                {
                                    tmpFields[fieldIndex].SetValue(target, 0, null);
                                }

                                break;

                            case TypeCode.String:
                                if (kk != null)
                                {
                                    tmpFields[fieldIndex].SetValue(target, workSheet.GetValue<string>(i + 1, j + 1),
                                        null);
                                }
                                else
                                {
                                    tmpFields[fieldIndex].SetValue(target, "", null);
                                }

                                break;

                            case TypeCode.Single:
                                if (kk != null)
                                {
                                    try
                                    {

                                        if (string.IsNullOrEmpty(value))
                                        {
                                            value = "0";
                                        }

                                        tmpFields[fieldIndex].SetValue(target, float.Parse(value), null);
                                    }
                                    catch (System.Exception ex)
                                    {
                                        Debug.LogError(ex.ToString());
                                        Debug.LogError(string.Format("Data error: {0} : {2}:[{1}] is not float", name,
                                            workSheet.GetValue<string>(i + 1, j + 1), tmpFields[j].Name));
                                    }

                                }
                                else
                                {
                                    tmpFields[fieldIndex].SetValue(target, 0, null);
                                }

                                break;
                            case TypeCode.Boolean:
                                tmpFields[fieldIndex].SetValue(target, workSheet.GetValue<string>(i + 1, j + 1), null);
                                break;
                            default:
                                break;
                        }

                        fieldIndex++;
                    }

                    mDataList.Add(target);
                }
            }
            return configObj;
        }
        
        private static Type GetTypeByName(string str)
        {
            Type typ = Type.GetType(str + ",Assembly-CSharp-firstpass");
            if (typ == null)
            {
                typ = Type.GetType(str + ",Assembly-CSharp");
                if (typ == null)
                {
                    Debug.LogError("not find!!! ");
                    return null;
                }
            }
            return typ;
        }

        #endregion

        private static void CheckHash(ExcelItem excel)
        {
            excel.Type = ExcelType.Normal;
            excel.Select = false;
            if (HashConfig.TryGetExcelInfo(excel.Name, out var excelInfo))
            {
                excelInfo.Hash = excel.Hash;
                return;
            }
            HashConfig.Add(excel.Name, excel.Hash);
        }
    }
}